package com.czmc.wifivideo.net.udp

import com.czmc.wifivideo.log
import com.czmc.wifivideo.net.Receiver
import com.czmc.wifivideo.net.Scanner
import com.czmc.wifivideo.net.Sender
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.concurrent.timerTask

/**
 * @author czmc
 * @version 1.0
 * @email: chenzhiming@dkhs.com
 * @description TODO
 * @date 12/5/2018
 */

class UDPScanner(val broadcaster: Sender = UDPSender(), val broadreceiver: Receiver = UDPReceiver(),val locallistener: Receiver = UDPReceiver(port = Constant.PORT_RESPONSE_SEND), val callback: (List<SearchResult>) -> Unit = {}) :Runnable,Scanner {
    var isStart:Boolean = false
    val queue: ConcurrentLinkedQueue<UDPSender> = ConcurrentLinkedQueue()
    override fun start() {
        if(!isStart) {
            isStart = true
            Thread(this).start()
        }
    }

    override fun stop() {
        timer?.cancel()
        isStart = false
    }

    private val results = Collections.synchronizedList(arrayListOf<SearchResult>())
    private var timer:Timer? =null

    override fun run() {
        timer = Timer()
        timer?.schedule(timerTask {
            if(!isStart) return@timerTask
            val sleep:()->Unit ={
                Thread.sleep((Math.random()*1000).toLong())
            }
            sleep()
            doBroadcast()
            sleep()
            doLocalListenerReceive()
            queue.poll()?.send("pong")

        },1000, 5000)
        while (isStart){
            doBroadcastReceiveAndResponse()
        }
    }

    /**
     * 广播3次
     */
    fun doBroadcast() {
        log("doBroadcast")
        for (i in 0..3){
            //broadcast
            broadcaster.send("ping")
        }
    }

    fun doLocalListenerReceive(){
        log("doLocalListenerReceive")
        var listenerResult  = locallistener.receive()
        listenerResult?.apply{
            log(this.toString())
            if(this?.data?.startsWith("pong") && !results.contains(this)){
                results.add(this)
                if (callback != null) {
                    callback(results)
                }
            }
        }
    }

    fun doBroadcastReceiveAndResponse() {
        log("doBroadcastReceiveAndResponse")
        var result  = broadreceiver.receive()
        result?.apply{
            log(this.toString())
            if(this.data?.startsWith("ping") && !results.contains(this)) {
                results.add(this)
                if (callback != null) {
                    callback(results)
                }
                queue.add(UDPSender(this.ip, Constant.PORT_RESPONSE_SEND))
            }
        }
    }


}